package server.sprite;

import java.util.Vector;

import client.game.Game;

import server.player.Player;


import general.datastructures.Rectangle;
import general.datastructures.Vector2f;
import general.interfaces.IMovable;

//TODO change to abstract class, use class like Unit for real movable sprite
public class MovableSprite extends Sprite implements IMovable {

	private Vector<Vector2f> wc_waypoints = new Vector<Vector2f>();
	private final float speed;
	private Vector2f wc_movedir = new Vector2f(0);
	private boolean isMoving = false;
	
	public MovableSprite(Game g, String name, String ref, Vector2f wc_position, float speed, Player owner) {
		super(g,name,ref, owner);
		this.wc_position = wc_position;
		this.speed = speed;
	}

	@Override
	public double getFuelAmount() {
		return 0;
	}

	@Override
	public double refuel(double amount) {
		return 0;
	}

	@Override
	public Vector2f getPosition() {
		synchronized (wc_position) {
			return this.wc_position;
		}
	}

	@Override
	public Vector<Vector2f> getWaypoints(){
		synchronized (wc_waypoints) {
			return wc_waypoints;
		}
	}

	public void addWaypoint(Vector2f wc_waypoint)
	{
		System.out.println(this);
		synchronized (wc_waypoints) {
			this.wc_waypoints.add(wc_waypoint);
		}
		this.continueMoving();

	}
		
	@Override
	public synchronized void appendWaypoints(Vector<Vector2f> wc_waypoints)
	{

		if(wc_waypoints.size()>0)
		{
		
			for(Vector2f wc_v : wc_waypoints)
			{
				if(wc_v!=null)
				{
					this.wc_waypoints.add(wc_v);
				}
			}
				
			if(!isMoving)
			{
				this.wc_movedir = Vector2f.subtract(this.wc_waypoints.firstElement(), wc_position);
				this.wc_movedir.normalize();
				this.isMoving = true;
			}
		}
	}

	@Override
	public synchronized void setWaypoints(Vector<Vector2f> wc_waypoints)
	{
		this.wc_waypoints = getWaypoints();
		
		this.wc_movedir = Vector2f.subtract(this.wc_waypoints.firstElement(), wc_position);
		this.wc_movedir.normalize();
		
		this.isMoving = true;
	}	
	
	@Override
	public void update(long gametime) {
		
		//System.out.println("Sprite update: "+gametime);
		
		if(isMoving)
		{
			/*if((gametime>0.1)&&(speed>0))
			{
				System.out.println(this.getName() +": " + speed*((gametime)/10));
			}*/
			
			if(this.wc_position.isInRange(this.wc_waypoints.firstElement(), 1.2f*(float)speed*(((float)gametime)/10)))
			{
				this.wc_waypoints.remove(0);
				System.out.println(this.wc_waypoints);
				System.out.println(this.wc_waypoints.isEmpty());
				if(!wc_waypoints.isEmpty())
				{
					this.wc_movedir = Vector2f.subtract(this.wc_waypoints.firstElement(), wc_position);
					this.wc_movedir.normalize();
				}
				else
				{
					this.isMoving = false;
					wc_movedir = new Vector2f(0);
				}
			}
			
			Vector<Sprite> collidingSprites = this.collides(this.wc_position.add_cpy(wc_movedir.scale_cpy((float)speed*(((float)gametime)/10))));
			
			if(collidingSprites.isEmpty())
			{
				this.wc_position.add(wc_movedir.scale_cpy((float)speed*(((float)gametime)/10)));
			}
			else
			{
				avoidCollision(collidingSprites);
			}
		}
		else
		{
			try {
				Thread.sleep(10);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public static MovableSprite MovableSpriteCreator()
	{
		return null;
	}

	@Override
	public void stopMoving() {
		this.isMoving = false;
	}

	@Override
	public void continueMoving() {
		synchronized (wc_waypoints) {
			if (!this.wc_waypoints.isEmpty())
			{
				this.isMoving = true;
			}
		}
	}
	
	public boolean isMoving()
	{
		return this.isMoving;
	}
	
	private Vector<Sprite> collides(Vector2f wc_targetpos)
	{
		Vector<Sprite> collidingSprites = new Vector<Sprite>();
		for(Sprite s: g.getUnitManager().getSprites())
		{
			if(s.equals(this))
			{
				continue;
			}
			if(s.getCollisionRectangle().intersects(new Rectangle(wc_targetpos, getWidth(), getHeight())))
			{
				System.out.println("Kollision: "+this.getName()+" ist mit "+s.getName()+" kollidiert!");
				collidingSprites.add(s);
			}
		}
		
		return collidingSprites;
	}
	
	private void avoidCollision(Vector<Sprite> collidingSprites)
	{
		
	}

}
